Skip to content

Conversation

@nvazquez
Copy link
Contributor

@nvazquez nvazquez commented Jan 21, 2026

Description

This PR extends the conserve mode for VPCs tiers added on the previous PRs: #8309, #10744 by allowing:

  • If the VPC tier offering uses conserve mode, then the public IP used for Source NAT can be reused for multiple services (it was previously restricted to Source NAT only)

This PR also introduces the following changes:

  • Introduce conserve mode for VPC offerings
  • When a VPC is created from a VPC offering using conserve mode: public IP rules can be created on different VPC tiers (when conserve mode = false, the rules are restricted to a single VPC tier).

Fixes: #8317

Types of changes

  • Breaking change (fix or feature that would cause existing functionality to change)
  • New feature (non-breaking change which adds functionality)
  • Bug fix (non-breaking change which fixes an issue)
  • Enhancement (improves an existing feature and functionality)
  • Cleanup (Code refactoring and cleanup, that may add test cases)
  • Build/CI
  • Test (unit or integration test code)

Feature/Enhancement Scale or Bug Severity

Feature/Enhancement Scale

  • Major
  • Minor

Bug Severity

  • BLOCKER
  • Critical
  • Major
  • Minor
  • Trivial

Screenshots (if appropriate):

How Has This Been Tested?

How did you try to break this feature and the system with this change?

@nvazquez
Copy link
Contributor Author

@blueorangutan package

@blueorangutan
Copy link

@nvazquez a [SL] Jenkins job has been kicked to build packages. It will be bundled with no SystemVM templates. I'll keep you posted as I make progress.

@codecov
Copy link

codecov bot commented Jan 21, 2026

Codecov Report

❌ Patch coverage is 6.89655% with 54 lines in your changes missing coverage. Please review.
✅ Project coverage is 17.85%. Comparing base (1b0a036) to head (45eba18).
⚠️ Report is 132 commits behind head on main.

Files with missing lines Patch % Lines
...om/cloud/network/firewall/FirewallManagerImpl.java 14.28% 7 Missing and 5 partials ⚠️
...n/java/com/cloud/network/IpAddressManagerImpl.java 0.00% 8 Missing and 2 partials ⚠️
...e/cloudstack/api/response/VpcOfferingResponse.java 0.00% 6 Missing ⚠️
...main/java/com/cloud/network/vpc/VpcOfferingVO.java 0.00% 6 Missing ⚠️
...ck/api/command/admin/vpc/CreateVPCOfferingCmd.java 0.00% 3 Missing ⚠️
...rg/apache/cloudstack/api/response/VpcResponse.java 0.00% 3 Missing ⚠️
...java/com/cloud/api/query/vo/VpcOfferingJoinVO.java 0.00% 3 Missing ⚠️
...loud/network/lb/LoadBalancingRulesManagerImpl.java 0.00% 3 Missing ⚠️
...ain/java/com/cloud/network/vpc/VpcManagerImpl.java 40.00% 2 Missing and 1 partial ⚠️
...and/user/firewall/CreatePortForwardingRuleCmd.java 0.00% 1 Missing ⚠️
... and 4 more
Additional details and impacted files
@@            Coverage Diff             @@
##               main   #12487    +/-   ##
==========================================
  Coverage     17.84%   17.85%            
- Complexity    15980    15997    +17     
==========================================
  Files          5929     5930     +1     
  Lines        531084   531511   +427     
  Branches      64914    64989    +75     
==========================================
+ Hits          94783    94882    +99     
- Misses       425686   425999   +313     
- Partials      10615    10630    +15     
Flag Coverage Δ
uitests 3.58% <ø> (-0.01%) ⬇️
unittests 18.94% <6.89%> (+<0.01%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@blueorangutan
Copy link

Packaging result [SF]: ✖️ el8 ✖️ el9 ✖️ debian ✖️ suse15. SL-JID 16471

@nvazquez
Copy link
Contributor Author

@blueorangutan package

@blueorangutan
Copy link

@nvazquez a [SL] Jenkins job has been kicked to build packages. It will be bundled with no SystemVM templates. I'll keep you posted as I make progress.

@blueorangutan
Copy link

Packaging result [SF]: ✖️ el8 ✖️ el9 ✔️ debian ✖️ suse15. SL-JID 16473

@nvazquez
Copy link
Contributor Author

@blueorangutan package

@blueorangutan
Copy link

@nvazquez a [SL] Jenkins job has been kicked to build packages. It will be bundled with no SystemVM templates. I'll keep you posted as I make progress.

@blueorangutan
Copy link

Packaging result [SF]: ✔️ el8 ✔️ el9 ✔️ el10 ✖️ debian ✔️ suse15. SL-JID 16475

@nvazquez
Copy link
Contributor Author

@blueorangutan test keepEnv

@blueorangutan
Copy link

@nvazquez a [SL] Trillian-Jenkins test job (ol8 mgmt + kvm-ol8) has been kicked to run smoke tests

@blueorangutan
Copy link

[SF] Trillian test result (tid-15239)
Environment: kvm-ol8 (x2), zone: Advanced Networking with Mgmt server ol8
Total time taken: 55566 seconds
Marvin logs: https://github.com/blueorangutan/acs-prs/releases/download/trillian/pr12487-t15239-kvm-ol8.zip
Smoke tests completed. 147 look OK, 3 have errors, 0 did not run
Only failed and skipped tests results shown below:

Test Result Time (s) Test File
test_03_deploy_and_scale_kubernetes_cluster Failure 26.70 test_kubernetes_clusters.py
test_02_list_cpvm_vm Failure 0.03 test_ssvm.py
test_04_cpvm_internals Failure 0.04 test_ssvm.py
test_01_redundant_vpc_site2site_vpn Failure 392.36 test_vpc_vpn.py

@nvazquez nvazquez marked this pull request as ready for review January 27, 2026 05:09
@nvazquez nvazquez added this to the 4.23.0 milestone Jan 27, 2026
@nvazquez nvazquez changed the title Fix conserve mode for VPC Source NAT IP and extend rules for VPC tiers Fix conserve mode for VPC Source NAT IP and extend conserve mode for VPC offerings Jan 27, 2026
@nvazquez
Copy link
Contributor Author

@blueorangutan package

@blueorangutan
Copy link

@nvazquez a [SL] Jenkins job has been kicked to build packages. It will be bundled with no SystemVM templates. I'll keep you posted as I make progress.

@blueorangutan
Copy link

@sureshanaparti a [SL] Jenkins job has been kicked to build packages. It will be bundled with no SystemVM templates. I'll keep you posted as I make progress.

@blueorangutan
Copy link

Packaging result [SF]: ✔️ el8 ✔️ el9 ✔️ el10 ✖️ debian ✔️ suse15. SL-JID 16549

@weizhouapache
Copy link
Member

@blueorangutan package

@blueorangutan
Copy link

@weizhouapache a [SL] Jenkins job has been kicked to build packages. It will be bundled with no SystemVM templates. I'll keep you posted as I make progress.

Copy link
Member

@weizhouapache weizhouapache left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@nvazquez

  • can we create VPC offering with conserve mode via API and UI ?
  • can you add smoke tests ?
    • source nat can be used by vpc tiers
    • other public Ips too

@blueorangutan
Copy link

Packaging result [SF]: ✔️ el8 ✔️ el9 ✔️ el10 ✔️ debian ✔️ suse15. SL-JID 16553

@nvazquez nvazquez marked this pull request as draft January 27, 2026 15:11
@nvazquez nvazquez changed the title Fix conserve mode for VPC Source NAT IP and extend conserve mode for VPC offerings Add conserve mode for VPC offerings Jan 29, 2026
Comment on lines +461 to 469
// (except for VPCs with conserve mode = true)
if ((!isNewRuleOnVpcNetwork || !isVpcConserveModeEnabled)
&& rule.getNetworkId() != newRule.getNetworkId() && rule.getState() != State.Revoke) {
String errMsg = String.format("New rule is for a different network than what's specified in rule %s", rule.getXid());
if (isNewRuleOnVpcNetwork) {
errMsg += String.format(" - VPC id=%s is not using conserve mode", newRuleNetwork.getVpcId());
}
throw new NetworkRuleConflictException(errMsg);
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

new method

Comment on lines +402 to +411
NetworkVO newRuleNetwork = _networkDao.findById(newRule.getNetworkId());
if (newRuleNetwork == null) {
throw new InvalidParameterValueException("Unable to create firewall rule as cannot find network by id=" + newRule.getNetworkId());
}
boolean isNewRuleOnVpcNetwork = newRuleNetwork.getVpcId() != null;
boolean isVpcConserveModeEnabled = false;
if (isNewRuleOnVpcNetwork) {
VpcOfferingVO vpcOffering = vpcOfferingDao.findById(newRuleNetwork.getVpcId());
isVpcConserveModeEnabled = vpcOffering != null && vpcOffering.isConserveMode();
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

new method(s)?

@RosiKyu RosiKyu self-assigned this Jan 29, 2026
Copy link
Collaborator

@RosiKyu RosiKyu left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

PR needs some fixes:

Issues Identified:

  1. The conservemode parameter is not being passed from API command to the service layer (value not saved to DB)
  2. The conservemode field is not being returned in the API response (VpcOfferingResponse)

TC1: Create VPC Offering with Conserve Mode = true

Objective: Verify VPC offering can be created with conserve mode enabled and the field is properly stored and returned via API.

Test Steps:

  1. Create VPC offering with conservemode=true parameter
  2. Verify the offering via list vpcofferings API
  3. Verify the value is stored correctly in the database

Expected Result:

  • VPC offering is created successfully
  • API response includes conservemode: true
  • Database shows conserve_mode = 1

Actual Result:

  • VPC offering created successfully with ID b9b783b2-b1fb-4588-b383-ff36cc9e54ab
  • BUG: API response does NOT include conservemode field at all
  • BUG: Database shows conserve_mode = 0 instead of 1 despite passing conservemode=true

Status: Failed

Test Evidence:

(localcloud) 🐱 > create vpcoffering name="Test-Conserve-Mode-VPC-Offering" displaytext="VPC Offering with Conserve Mode Enabled" supportedservices="Dhcp,Dns,SourceNat,PortForwarding,Lb,UserData,StaticNat,NetworkACL" conservemode=true
{
  "vpcoffering": {
    "created": "2026-01-30T09:02:54+0000",
    "displaytext": "VPC Offering with Conserve Mode Enabled",
    "distributedvpcrouter": false,
    "fornsx": false,
    "id": "b9b783b2-b1fb-4588-b383-ff36cc9e54ab",
    "internetprotocol": "IPv4",
    "isdefault": false,
    "name": "Test-Conserve-Mode-VPC-Offering",
    "service": [
      {
        "name": "Dhcp",
        "provider": [
          {
            "name": "VpcVirtualRouter"
          }
        ]
      },
      {
        "name": "StaticNat",
        "provider": [
          {
            "name": "VpcVirtualRouter"
          }
        ]
      },
      {
        "name": "UserData",
        "provider": [
          {
            "name": "VpcVirtualRouter"
          }
        ]
      },
      {
        "name": "SourceNat",
        "provider": [
          {
            "name": "VpcVirtualRouter"
          }
        ]
      },
      {
        "name": "Lb",
        "provider": [
          {
            "name": "VpcVirtualRouter"
          }
        ]
      },
      {
        "name": "NetworkACL",
        "provider": [
          {
            "name": "VpcVirtualRouter"
          }
        ]
      },
      {
        "name": "Dns",
        "provider": [
          {
            "name": "VpcVirtualRouter"
          }
        ]
      },
      {
        "name": "PortForwarding",
        "provider": [
          {
            "name": "VpcVirtualRouter"
          }
        ]
      }
    ],
    "specifyasnumber": false,
    "state": "Disabled",
    "supportsregionLevelvpc": false
  }
}

(localcloud) 🐱 > list vpcofferings name="Test-Conserve-Mode-VPC-Offering"
{
  "count": 1,
  "vpcoffering": [
    {
      "created": "2026-01-30T09:02:54+0000",
      "displaytext": "VPC Offering with Conserve Mode Enabled",
      "distributedvpcrouter": false,
      "fornsx": false,
      "id": "b9b783b2-b1fb-4588-b383-ff36cc9e54ab",
      "internetprotocol": "IPv4",
      "isdefault": false,
      "name": "Test-Conserve-Mode-VPC-Offering",
      "service": [...],
      "specifyasnumber": false,
      "state": "Disabled",
      "supportsregionLevelvpc": false
    }
  ]
}

mysql> SELECT id, name, conserve_mode FROM cloud.vpc_offerings WHERE name='Test-Conserve-Mode-VPC-Offering';
+----+---------------------------------+---------------+
| id | name                            | conserve_mode |
+----+---------------------------------+---------------+
|  8 | Test-Conserve-Mode-VPC-Offering |             0 |
+----+---------------------------------+---------------+
1 row in set (0.00 sec)

@nvazquez
Copy link
Contributor Author

@blueorangutan package

@blueorangutan
Copy link

@nvazquez a [SL] Jenkins job has been kicked to build packages. It will be bundled with no SystemVM templates. I'll keep you posted as I make progress.

@blueorangutan
Copy link

Packaging result [SF]: ✔️ el8 ✔️ el9 ✔️ el10 ✔️ debian ✔️ suse15. SL-JID 16654

@nvazquez
Copy link
Contributor Author

@blueorangutan test

@blueorangutan
Copy link

@nvazquez a [SL] Trillian-Jenkins test job (ol8 mgmt + kvm-ol8) has been kicked to run smoke tests

@blueorangutan
Copy link

[SF] Trillian test result (tid-15348)
Environment: kvm-ol8 (x2), zone: Advanced Networking with Mgmt server ol8
Total time taken: 49809 seconds
Marvin logs: https://github.com/blueorangutan/acs-prs/releases/download/trillian/pr12487-t15348-kvm-ol8.zip
Smoke tests completed. 147 look OK, 3 have errors, 0 did not run
Only failed and skipped tests results shown below:

Test Result Time (s) Test File
ContextSuite context=TestListIdsParams>:teardown Error 1.15 test_list_ids_parameter.py
test_01_snapshot_root_disk Error 5.95 test_snapshots.py
test_02_list_snapshots_with_removed_data_store Error 48.80 test_snapshots.py
test_02_list_snapshots_with_removed_data_store Error 48.80 test_snapshots.py
ContextSuite context=TestSnapshotStandaloneBackup>:teardown Error 27.75 test_snapshots.py
test_01_snapshot_usage Error 25.80 test_usage.py
test_01_vpn_usage Error 1.10 test_usage.py

@nvazquez
Copy link
Contributor Author

nvazquez commented Feb 1, 2026

@blueorangutan test keepEnv

@blueorangutan
Copy link

@nvazquez a [SL] Trillian-Jenkins test job (ol8 mgmt + kvm-ol8) has been kicked to run smoke tests

@blueorangutan
Copy link

[SF] Trillian test result (tid-15355)
Environment: kvm-ol8 (x2), zone: Advanced Networking with Mgmt server ol8
Total time taken: 50545 seconds
Marvin logs: https://github.com/blueorangutan/acs-prs/releases/download/trillian/pr12487-t15355-kvm-ol8.zip
Smoke tests completed. 147 look OK, 3 have errors, 0 did not run
Only failed and skipped tests results shown below:

Test Result Time (s) Test File
ContextSuite context=TestListIdsParams>:teardown Error 1.11 test_list_ids_parameter.py
test_01_snapshot_root_disk Error 8.04 test_snapshots.py
test_02_list_snapshots_with_removed_data_store Error 48.59 test_snapshots.py
test_02_list_snapshots_with_removed_data_store Error 48.59 test_snapshots.py
ContextSuite context=TestSnapshotStandaloneBackup>:teardown Error 29.53 test_snapshots.py
test_01_snapshot_usage Error 28.82 test_usage.py
test_01_vpn_usage Error 1.09 test_usage.py

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR extends “IP conserve mode” behavior into VPC offerings and relaxes certain per-tier restrictions so that, when conserve mode is enabled, a VPC’s Source NAT public IP can be reused for additional services and public-IP rules can be created across multiple VPC tiers.

Changes:

  • Add conservemode to VPC offerings end-to-end (DB schema/view/entity, API params/responses, UI create form + details).
  • Adjust backend rule/network selection and conflict checks to allow cross-tier usage in VPC conserve mode (PF/LB/firewall paths).
  • Update UI logic for Public IP / PF / LB screens to reflect conserve-mode behavior (tier selection and tab availability).

Reviewed changes

Copilot reviewed 26 out of 26 changed files in this pull request and generated 7 comments.

Show a summary per file
File Description
ui/src/views/offering/AddVpcOffering.vue Adds a Conserve Mode switch and passes conservemode to createVPCOffering.
ui/src/views/network/PublicIpResource.vue Changes tab filtering for VPC SourceNAT IPs based on VPC offering conserve mode.
ui/src/views/network/PortForwarding.vue Allows tier selection when VPC conserve mode is enabled; uses VPC offering conserve mode flag.
ui/src/views/network/LoadBalancing.vue Allows tier selection when VPC conserve mode is enabled; uses VPC offering conserve mode flag.
ui/src/config/section/offering.js Shows conservemode in VPC offering details.
server/src/main/java/com/cloud/network/firewall/FirewallManagerImpl.java Relaxes cross-network firewall-rule conflict restriction for VPC conserve mode.
server/src/test/java/com/cloud/network/firewall/FirewallManagerTest.java Updates unit test setup for new network lookup in conflict detection.
server/src/main/java/com/cloud/network/lb/LoadBalancingRulesManagerImpl.java Threads a networkId parameter to support VPC-tier-aware LB creation.
engine/components-api/src/main/java/com/cloud/network/lb/LoadBalancingRulesManager.java Updates API surface to include networkId parameter.
server/src/main/java/com/cloud/network/IpAddressManagerImpl.java Adjusts Source NAT detection when associating IPs within VPCs.
api/src/main/java/org/apache/cloudstack/api/command/admin/vpc/CreateVPCOfferingCmd.java Adds conservemode parameter for VPC offering creation.
engine/schema/src/main/java/com/cloud/network/vpc/VpcOfferingVO.java Persists conserve_mode on VPC offerings.
engine/schema/src/main/resources/META-INF/db/schema-42210to42300.sql Adds conserve_mode column to vpc_offerings.
engine/schema/src/main/resources/META-INF/db/views/cloud.vpc_offering_view.sql Exposes conserve_mode via VPC offering DB view.
server/src/main/java/com/cloud/api/query/vo/VpcOfferingJoinVO.java Exposes conserve_mode on the VPC offering join view VO.
server/src/main/java/com/cloud/api/query/dao/VpcOfferingJoinDaoImpl.java Populates conserve mode in VpcOfferingResponse.
api/src/main/java/org/apache/cloudstack/api/response/VpcOfferingResponse.java Adds conservemode field to VPC offering response.
api/src/main/java/org/apache/cloudstack/api/response/VpcResponse.java Adds vpcofferingconservemode field to VPC response.
server/src/main/java/com/cloud/api/ApiResponseHelper.java Sets vpcofferingconservemode in VPC response.
api/src/main/java/org/apache/cloudstack/api/ApiConstants.java Adds vpcofferingconservemode constant.
api/src/main/java/com/cloud/network/vpc/VpcOffering.java Adds isConserveMode() to VPC offering interface.
api/src/main/java/com/cloud/network/vpc/VpcProvisioningService.java Extends createVpcOffering signature to include conserve mode.
server/src/main/java/com/cloud/network/vpc/VpcManagerImpl.java Plumbs conserve mode into VPC offering creation/persist.
api/src/main/java/org/apache/cloudstack/api/command/user/firewall/CreatePortForwardingRuleCmd.java Adjusts network-id resolution behavior for VPC IPs.
plugins/network-elements/elastic-loadbalancer/.../LoadBalanceRuleHandler.java Updates LB manager call to include networkId.
plugins/network-elements/juniper-contrail/.../ContrailManagerImpl.java Updates VPC offering creation call signature.
Comments suppressed due to low confidence (1)

ui/src/views/network/PortForwarding.vue:649

  • The networkId selection logic for createPortForwardingRule is inverted due to parentheses: !('associatednetworkid' in this.resource || this.vpcConserveMode) becomes true only when BOTH there is no associated network AND conserve mode is false. This will incorrectly choose associatednetworkid when conserve mode is enabled (the opposite of what the UI/feature intends). Use the same condition used elsewhere in the file: no associated network OR vpcConserveMode => selectedTier; otherwise associatednetworkid.
      this.loading = true
      this.addVmModalVisible = false
      const networkId = ('vpcid' in this.resource && (!('associatednetworkid' in this.resource || this.vpcConserveMode))) ? this.selectedTier : this.resource.associatednetworkid
      postAPI('createPortForwardingRule', {
        ...this.newRule,
        ipaddressid: this.resource.id,
        networkid: networkId

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines 402 to 468
@@ -443,8 +458,14 @@ public void detectRulesConflict(FirewallRule newRule) throws NetworkRuleConflict
}

// Checking if the rule applied is to the same network that is passed in the rule.
if (rule.getNetworkId() != newRule.getNetworkId() && rule.getState() != State.Revoke) {
throw new NetworkRuleConflictException("New rule is for a different network than what's specified in rule " + rule.getXid());
// (except for VPCs with conserve mode = true)
if ((!isNewRuleOnVpcNetwork || !isVpcConserveModeEnabled)
&& rule.getNetworkId() != newRule.getNetworkId() && rule.getState() != State.Revoke) {
String errMsg = String.format("New rule is for a different network than what's specified in rule %s", rule.getXid());
if (isNewRuleOnVpcNetwork) {
errMsg += String.format(" - VPC id=%s is not using conserve mode", newRuleNetwork.getVpcId());
}
throw new NetworkRuleConflictException(errMsg);
Copy link

Copilot AI Feb 8, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The new VPC-conserve-mode branch in detectRulesConflict isn’t covered by unit tests: there are no assertions for (1) conserve mode enabled allowing rules across different VPC tiers and (2) conserve mode disabled still rejecting cross-network rules. Adding focused tests here would prevent regressions in the conflict detection logic.

Copilot uses AI. Check for mistakes.
Comment on lines 218 to 223
<span
v-if="'vpcid' in resource && !('associatednetworkid' in resource)">
v-if="'vpcid' in resource && (!('associatednetworkid' in resource) || this.vpcConserveMode)">
<strong>{{ $t('label.select.tier') }} </strong>
<a-select
:v-focus="'vpcid' in resource && !('associatednetworkid' in resource)"
:v-focus="'vpcid' in resource && (!('associatednetworkid' in resource) || this.vpcConserveMode)"
v-model:value="selectedTier"
Copy link

Copilot AI Feb 8, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Template expressions should not reference component state via this (in Vue 3 templates this is not in scope), so this.vpcConserveMode will evaluate incorrectly and can break the tier selector visibility/focus. Drop this. and reference vpcConserveMode directly in the v-if / focus expressions.

Copilot uses AI. Check for mistakes.
<strong>{{ $t('label.select.tier') }} </strong>
<a-select
:v-focus="'vpcid' in resource && !('associatednetworkid' in resource)"
:v-focus="'vpcid' in resource && (!('associatednetworkid' in resource) || this.vpcConserveMode)"
Copy link

Copilot AI Feb 8, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

:v-focus is treated as a bound attribute, not a directive. If the intent is to conditionally apply the focus directive, this should be v-focus="..." (matching the other uses of v-focus in the UI), otherwise it won’t do anything.

Suggested change
:v-focus="'vpcid' in resource && (!('associatednetworkid' in resource) || this.vpcConserveMode)"
v-focus="'vpcid' in resource && (!('associatednetworkid' in resource) || this.vpcConserveMode)"

Copilot uses AI. Check for mistakes.
getAPI('listNics', {
virtualmachineid: e.target.value,
networkId: ('vpcid' in this.resource && !('associatednetworkid' in this.resource)) ? this.selectedTier : this.resource.associatednetworkid
networkId: ('vpcid' in this.resource && (!('associatednetworkid' in this.resource) || this.vpcConserveMode)) ? this.selectedTier : this.resource.associatednetworkid
Copy link

Copilot AI Feb 8, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The listNics call uses networkId as the parameter name, but other listNics usages in the UI (and the API) use networkid. Using the wrong key can cause the backend to ignore the network filter and return the wrong NICs (or none). Rename the parameter to networkid for consistency with other calls.

Suggested change
networkId: ('vpcid' in this.resource && (!('associatednetworkid' in this.resource) || this.vpcConserveMode)) ? this.selectedTier : this.resource.associatednetworkid
networkid: ('vpcid' in this.resource && (!('associatednetworkid' in this.resource) || this.vpcConserveMode)) ? this.selectedTier : this.resource.associatednetworkid

Copilot uses AI. Check for mistakes.
Comment on lines 489 to 494
<span
v-if="'vpcid' in resource && !('associatednetworkid' in resource)">
v-if="'vpcid' in resource && (!('associatednetworkid' in resource) || this.vpcConserveMode)">
<strong>{{ $t('label.select.tier') }} </strong>
<a-select
v-focus="'vpcid' in resource && !('associatednetworkid' in resource)"
v-focus="'vpcid' in resource && (!('associatednetworkid' in resource) || this.vpcConserveMode)"
v-model:value="selectedTier"
Copy link

Copilot AI Feb 8, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same as PortForwarding.vue: this.vpcConserveMode in the template is not valid in Vue 3 template scope and can break the tier selector visibility/focus. Reference vpcConserveMode directly (without this).

Copilot uses AI. Check for mistakes.
Comment on lines 137 to 142
if (this.resource && this.resource.vpcid) {
// VPC IPs with source nat have only VPN
if (this.resource.issourcenat) {
const vpc = await this.fetchVpc()

// VPC IPs with source nat have only VPN when VPC offering conserve mode = false
if (this.resource.issourcenat && vpc.vpcofferingconservemode === false) {
this.tabs = this.defaultTabs.concat(this.$route.meta.tabs.filter(tab => tab.name === 'vpn'))
Copy link

Copilot AI Feb 8, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

filterTabs assumes fetchVpc always returns a VPC object and that vpcofferingconservemode is always present. If listVPCs returns no results (or the call fails), vpc can be null and vpc.vpcofferingconservemode will throw, leaving the page stuck loading. Also, comparing === false treats undefined as “conserve mode enabled”; for safer defaults/backwards compatibility, treat missing/undefined as false (i.e., restrict SourceNAT IPs unless the flag is explicitly true). Handle null/error from fetchVpc (try/catch or default object) and use a boolean-safe check.

Copilot uses AI. Check for mistakes.
Comment on lines +409 to +410
VpcOfferingVO vpcOffering = vpcOfferingDao.findById(newRuleNetwork.getVpcId());
isVpcConserveModeEnabled = vpcOffering != null && vpcOffering.isConserveMode();
Copy link

Copilot AI Feb 8, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In detectRulesConflict, the code uses newRuleNetwork.getVpcId() (a VPC id) to look up a VpcOffering via vpcOfferingDao.findById(...). This will query the vpc_offerings table by offering id and can return the wrong offering (or null), causing conserve mode detection to be incorrect. Fetch the VPC (e.g., via VpcDao using the VPC id from the network) and then look up the offering by vpc.getVpcOfferingId(), or otherwise resolve the offering id explicitly before calling vpcOfferingDao.

Suggested change
VpcOfferingVO vpcOffering = vpcOfferingDao.findById(newRuleNetwork.getVpcId());
isVpcConserveModeEnabled = vpcOffering != null && vpcOffering.isConserveMode();
com.cloud.network.vpc.VpcVO vpc = _entityMgr.findById(com.cloud.network.vpc.VpcVO.class, newRuleNetwork.getVpcId());
if (vpc != null && vpc.getVpcOfferingId() != null) {
VpcOfferingVO vpcOffering = vpcOfferingDao.findById(vpc.getVpcOfferingId());
isVpcConserveModeEnabled = vpcOffering != null && vpcOffering.isConserveMode();
}

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

VPC SourceNAT IPs can't be used for services (PF, LB, etc...)

6 participants